/************************************************************************************
<GoSlowDetection>  Copyright (C) <2021>  <Tao Kiang>
    This program comes with ABSOLUTELY NO WARRANTY;
    This is free software, and you are welcome to redistribute it
    under certain conditions;

    You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

    The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
************************************************************************************/
#include "myhook.h"
#include <QDebug>

static MyHook *hookClass = nullptr;  //与钩子绑定的对象的指针

//键盘钩子处理函数
LRESULT CALLBACK keyProc(int nCode,WPARAM wParam,LPARAM lParam) //钩子消息函数，系统消息队列信息会返回到该函数中
{
    if(!hookClass)
        return CallNextHookEx(hookClass->keyHook,nCode,wParam,lParam);

    if(WM_KEYDOWN == wParam)    //wParam用于判断事件类型，当前为按键按下事件
    {
        KBDLLHOOKSTRUCT* pkbhs = (KBDLLHOOKSTRUCT*)lParam;  //lParam用于判断按键类型
        if(pkbhs->vkCode == 0x31)   //检测按键1按下
        {
            //处理程序
        }
        if(pkbhs->vkCode == 0x31 && GetAsyncKeyState(VK_CONTROL))   //组合按键检测 按下Ctrl+1，哪个后按下的，使用GetAsyncKeyState函数判断
        {
            //处理程序
        }
        //qDebug()<<"key enter:"<<QString::number(pkbhs->vkCode,16);
        //可添加一些自定义信号发出去，如：emit hookClass->keyPress
    }
    if(WM_KEYUP == wParam)
    {
        KBDLLHOOKSTRUCT* pkbhs = (KBDLLHOOKSTRUCT*)lParam;  //lParam用于判断按键类型
        emit hookClass->keyPress(pkbhs->vkCode);
        qDebug()<<"key enter:"<<QString::number(pkbhs->vkCode,16);
    }

    return CallNextHookEx(hookClass->keyHook,nCode,wParam,lParam);     //继续原有的事件队列
}

//鼠标钩子处理函数
LRESULT CALLBACK mouseProc(int nCode,WPARAM wParam,LPARAM lParam) //钩子消息函数，系统消息队列信息会返回到该函数中
{
    if(!hookClass)
        return CallNextHookEx(hookClass->mouseHook,nCode,wParam,lParam);
    //鼠标点击右键
    if (WM_RBUTTONDOWN == wParam || WM_LBUTTONDOWN == wParam || WM_MBUTTONDOWN == wParam)// || WM_MOUSEWHEEL == wParam)
    {
        MOUSEHOOKSTRUCT *mhookstruct = (MOUSEHOOKSTRUCT*)lParam; //鼠标HOOK结构体
        POINT pt = mhookstruct->pt;         //将当前鼠标坐标点的x，y坐标作为参数向主程序窗口发送消息
        emit hookClass->mousePress(WM_RBUTTONDOWN == wParam,QPoint(pt.x,pt.y));
        qDebug()<<QString("mouse enter: %1 (%2,%3)").arg(WM_RBUTTONDOWN == wParam ? "R":"L").arg(pt.x).arg(pt.y);
    }

    return CallNextHookEx(hookClass->mouseHook,nCode,wParam,lParam);     //继续原有的事件队列
}

MyHook::MyHook()
    :mModel(eNull)
    ,keyHook(nullptr)
    ,mouseHook(nullptr)
{

}

MyHook::~MyHook()
{
    qDebug()<<Q_FUNC_INFO<<"relase MyHook";
}

MyHook *MyHook::instance()
{
    if(!hookClass)
        hookClass = new MyHook();
    return hookClass;
}

void MyHook::relase()
{
    if(hookClass)
    {
        hookClass->unInstallHook(mModel);
        delete hookClass;
        hookClass = nullptr;
    }
}

void MyHook::installHook(Model model) //安装钩子函数
{
    mModel = model;
    if(mModel | eKey)
        keyHook = SetWindowsHookEx(WH_KEYBOARD_LL,keyProc,nullptr,0);
    if(mModel | eMouse)
        mouseHook = SetWindowsHookEx(WH_MOUSE_LL,mouseProc,nullptr,0);
}

void MyHook::unInstallHook(Model model)    //删除钩子函数
{
    if(model | eKey)
        UnhookWindowsHookEx(keyHook);
    if(model | eMouse)
        UnhookWindowsHookEx(mouseHook);

    keyHook = nullptr;
    mouseHook = nullptr;
    mModel = eNull;
}

